import json
import logging

from ldap3 import Server, Connection, ALL_ATTRIBUTES

from airflow.configuration import conf

try:
    import pwd
except ImportError:
    pass

log = logging.getLogger(__name__)

cache = dict()


def create_conn(host, bind_dn=None, bind_passwd=None, port=389):
    server = Server(host=host, port=port)
    return Connection(server, bind_dn, bind_passwd, auto_bind=True)


def find_ldap_user_number(uid):
    try:
        if uid in cache:
            return cache[uid]
        else:
            conn = create_conn(conf.get('ldap', 'host'), bind_dn=conf.get('ldap', 'bind_dn'),
                               bind_passwd=conf.get('ldap', 'bind_password'))
            found = conn.search(search_base=conf.get('ldap', 'search_base'),
                                search_filter=conf.get('ldap', 'search_filter').format(uid),
                                attributes=['uid', 'cn', 'uidNumber', 'gidNumber'])
            if found:
                data = json.loads(conn.response_to_json())
                uid_number = data['entries'][0]['attributes']['uidNumber']
                cache[uid] = uid_number
                return cache[uid]
    except Exception as e:
        log.exception(e)
    return 1000


def get_user_id(name):
    try:
        for user in pwd.getpwall():
            if user[0] == name:
                return user[2]
    except Exception as e:
        pass
    return find_ldap_user_number(name)


def verify_username_password(username, password):
    conn = create_conn(conf.get('ldap', 'host'), bind_dn=conf.get('ldap', 'bind_dn'),
                       bind_passwd=conf.get('ldap', 'bind_password'))
    found = conn.search(search_base=conf.get('ldap', 'search_base'),
                        search_filter=conf.get('ldap', 'search_filter').format(username),
                        attributes=ALL_ATTRIBUTES)
    if found:
        entry = conn.response[0]
        dn = entry['dn']
        conn2 = Connection(conf.get('ldap', 'host'), user=dn, password=password, check_names=True, lazy=False, raise_exceptions=False)
        conn2.bind()
        if conn2.result["description"] == "success":
            return True
        else:
            return False

